/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include <algorithm>

#include "ViewManager.h"
#include "EntityView.h"
#include "Model.h"

#include "../shared/QuadTree.h"
#include "../shared/MFile.h"
#include "../game/StateFactory.h"
#include "../Kernel.h"

extern Kernel* g_kernel;

/*-------------------------------------------
    Sorting 
--------------------------------------------*/

// Sort based off of Y coord, the lower the Y, draw higher
 bool ViewSort(const EntityView* start, const EntityView* end) 
 {
     Vector2f startPosition = start->m_owner->m_physObject.GetPosition();
     Vector2f endPosition = end->m_owner->m_physObject.GetPosition();
    if ( start->m_owner->m_flags & EF_DRAWOVER && end->m_owner->m_flags & EF_DRAWOVER )
        return (startPosition.y < endPosition.y);

    if ( !(start->m_owner->m_flags & EF_DRAWOVER) && !(end->m_owner->m_flags & EF_DRAWOVER) )
        return (startPosition.y < endPosition.y);

    return (start->m_owner->m_flags & EF_DRAWOVER);

 }



ViewManager* ViewManager::instance = new ViewManager;

ViewManager::ViewManager(void)
{
    m_quadTree = NULL;
    Register();
}

/** Create a model for this entity */
EntityView* ViewManager::CreateView( IEntity* ent ) 
{ 
    EntityView* view = new EntityView(ent);

    view->SetRefID ( ent->GetID() ); 
    view->SetVisible( true );

    m_views.push_back( view );
    return view;
}


/** Create a view from a file */
bool ViewManager::ParseView( IEntity* ent, MFile* file )
{
    IResourceManagement* resource = g_kernel->GetResource();

    // create the view
    EntityView* view = CreateView( ent );

    file->ReadNext("{");
    file->ReadLine();

    std::string imageName = file->ReadNext(":");
    int row = file->ReadInt();
    int col = file->ReadInt();
    view->GetModel()->SetImage( resource->LoadImages( imageName, row, col ) );

    // read states
    bool rightBrace = false;
    while( !file->IsEnd() )
    {
        if ( file->Peek() == '}' )
        {
            rightBrace = true;
            break;
        }
        // create our model directions
        ModelDirections* dirs = new ModelDirections;

        std::string state   = file->ReadNext(":");
        std::string sound   = file->ReadNext(":");
        std::string script  = file->ReadNext(":");

        // get all four directions
        int nextUpdateTime = file->ReadInt();
        for ( int i = 0; i < 4; i++ ) 
        {
            int animTime        = file->ReadInt();
            int imageRow        = file->ReadInt();
            int imageCol        = file->ReadInt();
            int amount          = file->ReadInt();
            
            dirs->AddDirection( i, animTime, imageRow, imageCol, amount );
        }
        // add the state to the model
        view->GetModel()->AddState( state, dirs );
      
        State* entState = StateFactory::GetInstance()->CreateState( state );
        if ( sound != "null" && entState )
            entState->m_sound = resource->LoadSound( sound );
        if ( script != "null" && entState )
            entState->m_scriptFile = script;

        entState->m_nextUpdate = nextUpdateTime;
        ent->AddState( state, entState );
        file->ReadLine();
    }
    
    if ( !rightBrace )
    {
        g_kernel->LPrintf( ("**Error parsing Entity Models in: " + file->FileName() + " missing a closing \'}\' ").c_str() );
        g_kernel->LPrintf( "**On byte: %d of %d", file->GetPosition(), file->Size() );
        return true;
    }
    return false;   // no errors
}

ViewManager::~ViewManager(void)
{
    type_views::iterator it = m_views.begin();
    // remove each object
    for( ; it != m_views.end(); ++it )
    {
        //if( it->second )
        //    delete it->second;
        if( (*it) )
            delete (*it);
    }
    UnRegister();
}

/** Remove the view */
void ViewManager::RemoveView(int id) { 
    type_views::iterator it = m_views.begin();
    // render each object
    for( ; it != m_views.end(); ++it )
    {
        if( (*it)/*it->second*/->GetRefID() == id )
        {
            g_kernel->LPrintf( "--Deleting from ViewManager:: Releasing %d bytes", sizeof( (*it) ) );
            delete (*it); // it->second;
            m_views.erase( it );
            return;
        }
    } 
};

/** Remove the view */
void ViewManager::RemoveView( IView2D* v) 
{ 
    RemoveView( v->GetRefID() ); 
}

/** Update each view */
void ViewManager::Update(IRender *r, ICamera* cam)
{
    // current time
    float deltaTimeInMSec = g_kernel->GetFrameTime();

    //if ( quadTree )
    //{
    //    std::vector<IEntity*> visibleEntities;
    //    ICamera* cam = g_kernel->GetRenderer()->GetCamera(0);
    //    quadTree->GetObjects( cam->GetViewPort(), visibleEntities );

    //    size_t entSize = visibleEntities.size();
    //    std::vector<EntityView*> viewList;
    //    for(int i = 0; i < entSize; ++i )
    //    {
    //        EntityView* view = m_views[ visibleEntities[i]->GetID() ];
    //        if ( view )
    //        {
    //            viewList.push_back( view );
    //        }
    //    }
    //    // sort out the Y values for proper drawing
    //    std::sort( viewList.begin(), viewList.end(), ViewSort );
    //    size_t viewSize = viewList.size();
    //    for(int i =0;i< viewSize; ++i )
    //    {
    //        EntityView* view = viewList[i];
    //        // update the view
    //        view->Update(time);
    //        // now draw the view
    //        view->Render( r );
    //    }

    //}
    // sort out the Y values for proper drawing
    std::sort( m_views.begin(), m_views.end(), ViewSort );
    type_views::iterator it = m_views.begin();
    // render each object
    for( ; it != m_views.end(); ++it )
    {
        EntityView* view = (*it);//it->second;
        if ( cam->Contains( view->m_owner->GetBounds() ) )//view->m_owner->m_world.x+32, view->m_owner->m_world.y+32 ) )
        {
            // update the view
            view->Update( deltaTimeInMSec );
            // now draw the view
            view->Render( r, cam );
            
        }
    }
}

/** Handle an event */
bool ViewManager::HandleEvent( IEvent* e )
{
	bool success = false;
	switch( e->GetType() )
	{
	case EVT_ADD_ENTITY:
	    // addEntity( e->GetData<EntityAdditionData>()->m_entity );
	    success = true;
        
		break;
	case EVT_RM_ENTITY:
		RemoveView( e->GetData<EntityAdditionData>()->m_entity->GetID() );
		success = true;
		break;
	default:
        g_kernel->LPrintf( "ViewManager:: Could not handle event type: %d", e->GetType() );
		break;
	};
	return success;

}